package pl.edu.agh.pp.ldap;

import java.util.ArrayList;
import java.util.List;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;

import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;

public class UserDAO {
	
	private LdapTemplate ldapTemplate;
	
	private String userClassName = "p2pInetOrgPerson";
	private static String hostAttrName = "host";
	private static String filesAttrName = "files";
	
    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }
    
    public boolean create(User user) {
    	try{
    		ldapTemplate.bind(buildDn(user), null, buildAttributes(user));
    		return true;
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return false;
	}
    
    public void delete(User user) {
        DistinguishedName dn = new DistinguishedName(buildDn(user));
        ldapTemplate.unbind(dn);
    }
    
    public void update(User user) {
    	DirContextOperations ctx = ldapTemplate.lookupContext(buildDn(user));
    	ctx.setAttributeValue(hostAttrName, user.getAddress());
    	ctx.setAttributeValue(filesAttrName, user.getFiles());
    	ldapTemplate.modifyAttributes(ctx);
    }
    
    @SuppressWarnings("unchecked")
	public List<User> getAll() {     
    	return ldapTemplate.search("", "(objectclass="+userClassName+")",new UserAttributeMapper());
    }
    
    @SuppressWarnings("unchecked")
	public User getByAddress(String address) {
    	List<User> users = ldapTemplate.search("", "(&(objectclass="+userClassName+")("+hostAttrName+"="+address+"))",new UserAttributeMapper());
    	if(users.size()>0)
    		return users.get(0);
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	public User getByLogin(String login) {
    	List<User> users = ldapTemplate.search("", "(&(objectclass="+userClassName+")(cn="+login+"))",new UserAttributeMapper());
    	if(users.size()>0)
    		return users.get(0);
    	return null;
    }
    
	public boolean authenticate(User user) {
		AndFilter filter = new AndFilter();
		filter.and(new EqualsFilter("objectclass",userClassName)).and(new EqualsFilter("cn",user.getUsername()));
		return ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), user.getPassword());
	}
	
	private Attributes buildAttributes(User user) {
		Attributes attrs = new BasicAttributes();
		BasicAttribute ocattr = new BasicAttribute("objectclass");
		ocattr.add(userClassName);
		attrs.put(ocattr);
		
		attrs.put("cn",user.getUsername());
		attrs.put("sn",user.getUsername());
		attrs.put("userPassword",user.getPassword());
		attrs.put(hostAttrName, user.getAddress());
		//attrs.put(filesAttrName, user.getFiles());
		return attrs;
	}

	private String buildDn(User user) {
		return "cn="+user.getUsername();
	}
    
	private static class UserAttributeMapper implements AttributesMapper {
		@Override
		public Object mapFromAttributes(Attributes attributes) throws NamingException {
			User user = new User();
			String cn = (String) attributes.get("cn").get();
			if(cn!=null) user.setUsername(cn);
			Attribute address = attributes.get(hostAttrName);
	        if(address != null)
	            user.setAddress((String)address.get());
			Attribute files = attributes.get(filesAttrName);
	        if(files != null)
	            user.setFiles((String)files.get());
			return user;
		}
	}

	public List<String> getServersList() {
		List<String> serversList = new ArrayList<String>();
		for(User u : getAll()) {
			if(!u.getAddress().trim().isEmpty()) serversList.add(u.getAddress());
		}
		return serversList;
	}
	
}
